package com.java.spring.factory;

import com.java.spring.annotation.ComponentScan;
import com.java.spring.annotation.Lazy;
import com.java.spring.annotation.Service;
import com.java.spring.bean.BeanDefinition;
import com.java.spring.config.SpringConfig;
import com.java.spring.service.SysLogService;

import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class AnnotationConfigApplicationContext {
    private Map<String,Object> instanceMap = new HashMap<>();
    private Map<String,BeanDefinition> beanMap = new HashMap<>();

    public AnnotationConfigApplicationContext(Class<?> configCls) throws Exception {
        // 1、读取配置类中指定的包名
        final ComponentScan cs = configCls.getDeclaredAnnotation(ComponentScan.class);
        final String pkg = cs.value();
//        System.out.println(pkg);
        // 2、扫描指定包中的类
        final String classPath = pkg.replace(".", "/");
        final URL url = configCls.getClassLoader().getSystemResource(classPath);
        File fileDir = new File(url.getPath());

        final File[] classFile = fileDir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.isFile()&&file.getName().endsWith(".class");
            }
        });
        // 3、封装文件信息
        processClassFiles(pkg,classFile);
    }

    private void processClassFiles(String pkg, File[] classFile) throws Exception {
        for (File f : classFile) {
            String pkgClass = pkg+"."+f.getName().substring(0, f.getName().lastIndexOf("."));
//            System.out.println(pkgClass);
            Class<?> targetCls = Class.forName(pkgClass);
            final Service service = targetCls.getDeclaredAnnotation(Service.class);
            final Lazy lazy = targetCls.getDeclaredAnnotation(Lazy.class);
            if (service == null) continue;
            BeanDefinition bd = new BeanDefinition();
            bd.setId(service.value());
            bd.setPkgClass(pkgClass);
            if (lazy!=null){
                bd.setLazy(lazy.value());
            }
//            System.out.println(bd);
            beanMap.put(bd.getId(),bd);
            if (!bd.getLazy()){
                Object obj = newBeanInstance(targetCls);
                instanceMap.put(bd.getId(), obj);
            }
        }
    }
    public <T>T getBean(String key,Class<?> cls) throws Exception {
        Object obj = instanceMap.get(key);
        if (obj != null) {
            return (T)obj;
        }
        obj = newBeanInstance(cls);
        instanceMap.put(key, obj);
        return (T)obj;
    }

    private Object newBeanInstance(Class<?> targetCls) throws Exception {
        final Constructor<?> con = targetCls.getDeclaredConstructor();
        con.setAccessible(true);
        return con.newInstance();
    }

    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext ctx =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        SysLogService longService = ctx.getBean("sysLongService", SysLogService.class);
//        System.out.println("ls="+longService);
    }
}
